const STATUS = {
  PENDING: 0,
  FULFILLED: 1,
  REJECTED: 2,
}

class Promise {
  constructor (task) {
    this.status = STATUS.PENDING;

    this.resolveData = null;

    this.rejectData = null;

    this.onFulfilledList = [];

    this.onRejectedList = [];

    this.onResolve = (data) => {
      if (this.status === STATUS.PENDING) {
        this.status = STATUS.FULFILLED;
        this.resolveData = data;
        this.onFulfilledList.forEach(fn => {
          fn(this.rejectData)
        })
      }
    }

    this.onReject = (err) => {
      if (this.status === STATUS.PENDING) {
        this.status = STATUS.REJECTED;
        this.rejectData = err;
        this.onRejectedList.forEach(fn => {
          fn(this.rejectData)
        })
      }
    }

    this.resolvePromise = (data, resolve, reject) => {
      if (data instanceof Promise) {
        if (data.status === STATUS.PENDING) {
          data.then((val) => {
            this.resolvePromise(val, resolve, reject)
          }, reject)
        } else if (data.status === STATUS.FULFILLED) {
          resolve(data.resolveData);
        } else {
          reject(data.rejectData);
        }
      }
      else if (data !== null && data instanceof Object) {
        try {
          let then = data.then;
          if (then instanceof Function) {
            then.call(data, (val) => {
              this.resolvePromise(val, resolve, reject);
            }, reject);
          }
        } catch (e) {
          reject(e);
        }
      } else {
        resolve(data);
      }

      try {
        task(this.onResolve.bind(this), this.onReject.bind(this));
      } catch (e) {
        this.onReject(e)
      }
    }
  }

  then (onFulfilled, onRejected) {
    let promise;

    if (this.status === STATUS.PENDING) {
      promise = new Promise((resolve, reject) => {
        this.onFulfilledList.push(() => {
          if (!(onFulfilled instanceof Function)) {
            resolve(this.resolveData);
          } else {
            let data = onFulfilled(this.resolveData);
            this.resolvePromise(data, resolve, reject)
          }
        });

        this.onRejectedList.push(() => {
          if (!(onRejected instanceof Function)) {
            resolve(this.resolveData);
          } else {
            let data = onRejected(this.resolveData);
            this.resolvePromise(data, resolve, reject)
          }
        })
      })
    } else if (this.status === STATUS.FULFILLED) {
      promise = new Promise((resolve, reject) => {
        if (!(onFulfilled instanceof Function)) {
          resolve(this.resolveData)
        } else {
          let data = onFulfilled(this.resolveData)
          this.resolvePromise(data, resolve, reject)
        }
      })
    } else {
      promise = new Promise((resolve, reject) => {
        // 传入then的参数不是函数则忽略，直接reject
        if (!(onRejected instanceof Function)) {
          reject(this.rejectData)
        } else {
          let data = onRejected(this.rejectData)
          this.resolvePromise(data, resolve, reject)
        }
      })
    }

    return promise;
  }

  catch (rejectFn) {
    if (!rejectFn instanceof Function) {
      return
    }

    if (this.status === STATUS.PENDING) {
      this.onRejectedList.push(() => {
        if (this.rejectData !== null) {
          rejectFn(this.rejectData);
        }
      })
    } else if (this.status === STATUS.REJECTED) {
      if (this.rejectData !== null) {
        rejectFn(this.rejectData);
      }
    }
  }


  static resolve (value) {
    if (value instanceof Promise) return value;
    return new Promise((resolve, reject) => resolv(value));
  }

  static reject (value) {
    if (value instanceof Promise) return value
    return new Promise((resolve, reject) => reject(value));
  }


}
